package auth

import (
	"context"
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gcache"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/golang-jwt/jwt/v5"
	"time"
)

var jwtSecret = []byte(g.Cfg().MustGet(context.TODO(), "jwt.secret").String())
var expire = g.Cfg().MustGet(context.TODO(), "jwt.expire").Int()

type Claims struct {
	UserId   int64  `json:"user_id"`
	Username string `json:"username"`
	jwt.RegisteredClaims
}

// GenerateToken 生成JWT token
func GenerateAccessToken(userId int64, username string) (string, error) {
	now := time.Now()
	expireTime := now.Add(time.Duration(expire) * time.Second) // 7天过期
	claims := Claims{
		UserId:   userId,
		Username: username,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expireTime),
			IssuedAt:  jwt.NewNumericDate(now),
			Issuer:    "myapp",
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(jwtSecret)
}

// ParseToken 解析JWT token
func ParseToken(tokenString string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	}

	return nil, err
}

// 生成Refresh Token
func GenerateRefreshToken(userID int64) (string, error) {
	refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{
		ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expire) * time.Second)),
		IssuedAt:  jwt.NewNumericDate(time.Now()),
		Subject:   string(rune(userID)),
	})

	tokenString, err := refreshToken.SignedString(jwtSecret)
	if err != nil {
		return "", err
	}

	// 将refresh token存入缓存，设置过期时间
	err = gcache.Set(context.Background(), getRefreshTokenKey(userID, tokenString), true, time.Duration(expire)*time.Second)
	return tokenString, err
}

// 验证Access Token
func ValidateAccessToken(tokenString string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	}

	return nil, jwt.ErrInvalidKey
}

// 验证Refresh Token
func ValidateRefreshToken(tokenString string) (int64, error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})

	if err != nil || !token.Valid {
		return 0, err
	}

	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		return 0, jwt.ErrInvalidKey
	}

	sub, err := claims.GetSubject()
	if err != nil {
		return 0, err
	}
	userID := gconv.Int64(sub)
	// 检查refresh token是否在缓存中（是否有效）
	_, err = gcache.Get(context.Background(), getRefreshTokenKey(userID, tokenString))
	if err != nil {
		return 0, err
	}

	return userID, nil
}

// 使Refresh Token失效
func InvalidateRefreshToken(userID int64, tokenString string) error {
	_, err := gcache.Remove(context.Background(), getRefreshTokenKey(userID, tokenString))
	return err
}

// 使用户的所有Refresh Token失效
func InvalidateAllUserRefreshTokens(userID int64) error {
	// 这里需要根据实际存储方式实现
	// 如果是Redis，可以使用模式匹配删除
	return nil
}

func getRefreshTokenKey(userID int64, tokenString string) string {
	return fmt.Sprintf("refresh_token:%d:%s", userID, tokenString)
}
